Added support of service messages for polls.

This commit is contained in:
23rd
2026-03-26 21:47:29 +03:00
parent dc113c0620
commit 60ff46b012
10 changed files with 198 additions and 2 deletions
+4
View File
@@ -2528,6 +2528,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_action_todo_marked_not_done_self" = "You marked {tasks} as not done.";
"lng_action_todo_added" = "{from} added {tasks} to the list.";
"lng_action_todo_added_self" = "You added {tasks} to the list.";
"lng_action_poll_added_answer" = "{from} added \"{option}\" to the poll.";
"lng_action_poll_added_answer_self" = "You added \"{option}\" to the poll.";
"lng_action_poll_deleted_answer" = "{from} removed \"{option}\" from the poll.";
"lng_action_poll_deleted_answer_self" = "You removed \"{option}\" from the poll.";
"lng_action_todo_tasks_fallback#one" = "task";
"lng_action_todo_tasks_fallback#other" = "{count} tasks";
"lng_action_todo_tasks_and_one" = "{tasks}, {task}";
@@ -1803,6 +1803,8 @@ ServiceAction ParseServiceAction(
| ranges::views::transform(ParseTodoListItem)
| ranges::to_vector,
};
}, [&](const MTPDmessageActionPollAppendAnswer &data) {
result.content = ActionPollAppendAnswer{};
}, [&](const MTPDmessageActionSuggestedPostApproval &data) {
result.content = ActionSuggestedPostApproval{
.rejectComment = data.vreject_comment().value_or_empty(),
@@ -1879,7 +1881,23 @@ ServiceAction ParseServiceAction(
content.botId = data.vbot_id().v;
result.content = content;
}, [&](const MTPDmessageActionPollAppendAnswer &data) {
auto content = ActionPollAppendAnswer();
data.vanswer().match([&](const MTPDpollAnswer &answer) {
content.option = ParseString(answer.vtext().match(
[](const MTPDtextWithEntities &d) {
return d.vtext();
}));
}, [](const auto &) {});
result.content = content;
}, [&](const MTPDmessageActionPollDeleteAnswer &data) {
auto content = ActionPollDeleteAnswer();
data.vanswer().match([&](const MTPDpollAnswer &answer) {
content.option = ParseString(answer.vtext().match(
[](const MTPDtextWithEntities &d) {
return d.vtext();
}));
}, [](const auto &) {});
result.content = content;
}, [](const MTPDmessageActionEmpty &data) {});
return result;
}
@@ -718,6 +718,14 @@ struct ActionTodoAppendTasks {
std::vector<TodoListItem> items;
};
struct ActionPollAppendAnswer {
Utf8String option;
};
struct ActionPollDeleteAnswer {
Utf8String option;
};
struct ActionSuggestedPostApproval {
Utf8String rejectComment;
TimeId scheduleDate = 0;
@@ -809,6 +817,8 @@ struct ServiceAction {
ActionPaidMessagesPrice,
ActionTodoCompletions,
ActionTodoAppendTasks,
ActionPollAppendAnswer,
ActionPollDeleteAnswer,
ActionSuggestedPostApproval,
ActionSuggestedPostSuccess,
ActionSuggestedPostRefund,
@@ -1501,6 +1501,14 @@ auto HtmlWriter::Wrap::pushMessage(
+ "&quot;");
}
return serviceFrom + " added tasks: " + tasks.join(", ");
}, [&](const ActionPollAppendAnswer &data) {
return serviceFrom + " added &quot;"
+ data.option
+ "&quot; to the poll.";
}, [&](const ActionPollDeleteAnswer &data) {
return serviceFrom + " removed &quot;"
+ data.option
+ "&quot; from the poll.";
}, [&](const ActionSuggestedPostApproval &data) {
return serviceFrom
+ (data.rejected ? " rejected " : " approved ")
@@ -711,6 +711,14 @@ QByteArray SerializeMessage(
return result;
}) | ranges::to_vector;
pushBare("items", SerializeArray(context, items));
}, [&](const ActionPollAppendAnswer &data) {
pushActor();
pushAction("poll_append_answer");
push("option", data.option);
}, [&](const ActionPollDeleteAnswer &data) {
pushActor();
pushAction("poll_delete_answer");
push("option", data.option);
}, [&](const ActionSuggestedPostApproval &data) {
pushActor();
pushAction("process_suggested_post");
+37
View File
@@ -49,6 +49,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_document.h"
#include "data/data_histories.h"
#include "data/data_history_messages.h"
#include "api/api_text_entities.h"
#include "data/data_poll.h"
#include "data/data_todo_list.h"
#include "lang/lang_keys.h"
#include "apiwrap.h"
@@ -1429,6 +1431,41 @@ void History::applyServiceChanges(
}
}
}
}, [&](const MTPDmessageActionPollAppendAnswer &data) {
if (const auto append = item->Get<HistoryServicePollAppendAnswer>()) {
const auto list = append->msg
? append->msg
: owner().message(peer, append->msgId);
if (const auto media = list ? list->media() : nullptr) {
if (const auto poll = media->poll()) {
data.vanswer().match([&](const MTPDpollAnswer &answer) {
auto parsed = PollAnswer();
parsed.option = answer.voption().v;
parsed.text = Api::ParseTextWithEntities(
&session(),
answer.vtext());
if (!poll->answerByOption(parsed.option)) {
poll->answers.push_back(std::move(parsed));
}
}, [](const auto &) {});
}
}
}
}, [&](const MTPDmessageActionPollDeleteAnswer &data) {
if (const auto del = item->Get<HistoryServicePollDeleteAnswer>()) {
const auto list = del->msg
? del->msg
: owner().message(peer, del->msgId);
if (const auto media = list ? list->media() : nullptr) {
if (const auto poll = media->poll()) {
const auto option = del->answer.option;
auto &answers = poll->answers;
answers.erase(
ranges::remove(answers, option, &PollAnswer::option),
end(answers));
}
}
}
}, [&](const MTPDmessageActionStarGift &data) {
if (data.is_auction_acquired() && data.vto_id()) {
const auto to = peer->owner().peer(peerFromMTP(*data.vto_id()));
+95 -2
View File
@@ -866,6 +866,8 @@ HistoryServiceDependentData *HistoryItem::GetServiceDependentData() {
return done;
} else if (const auto append = Get<HistoryServiceTodoAppendTasks>()) {
return append;
} else if (const auto poll = Get<HistoryServicePollAppendAnswer>()) {
return poll;
} else if (const auto decision = Get<HistoryServiceSuggestDecision>()) {
return decision;
} else if (const auto finish = Get<HistoryServiceSuggestFinish>()) {
@@ -931,6 +933,8 @@ void HistoryItem::updateDependentServiceText() {
updateServiceText(prepareTodoCompletionsText());
} else if (Has<HistoryServiceTodoAppendTasks>()) {
updateServiceText(prepareTodoAppendTasksText());
} else if (Has<HistoryServicePollAppendAnswer>()) {
updateServiceText(preparePollAppendAnswerText());
}
}
@@ -947,6 +951,7 @@ void HistoryItem::updateServiceDependent(bool force) {
if (!dependent->lnk) {
auto todoItemId = 0;
auto pollOption = QByteArray();
if (const auto done = Get<HistoryServiceTodoCompletions>()) {
const auto &items = !done->completed.empty()
? done->completed
@@ -958,6 +963,10 @@ void HistoryItem::updateServiceDependent(bool force) {
if (append->list.size() == 1) {
todoItemId = append->list.front().id;
}
} else if (const auto pa = Get<HistoryServicePollAppendAnswer>()) {
pollOption = pa->answer.option;
} else if (const auto pd = Get<HistoryServicePollDeleteAnswer>()) {
pollOption = pd->answer.option;
}
dependent->lnk = JumpToMessageClickHandler(
(dependent->peerId
@@ -965,7 +974,7 @@ void HistoryItem::updateServiceDependent(bool force) {
: _history->peer),
dependent->msgId,
fullId(),
{ .todoItemId = todoItemId });
{ .todoItemId = todoItemId, .pollOption = pollOption });
}
auto gotDependencyItem = false;
if (!dependent->msg) {
@@ -4490,6 +4499,7 @@ void HistoryItem::createComponentsHelper(HistoryItemCommonFields &&fields) {
? replyTo.monoforumPeerId
: PeerId();
config.reply.todoItemId = replyTo.todoItemId;
config.reply.pollOption = replyTo.pollOption;
const auto replyToTop = replyTo.topicRootId
? replyTo.topicRootId
: LookupReplyToTop(_history, to);
@@ -4960,6 +4970,28 @@ void HistoryItem::createServiceFromMtp(const MTPDmessageService &message) {
) | ranges::views::transform([&](const MTPTodoItem &item) {
return TodoListItemFromMTP(session, item);
}) | ranges::to_vector;
} else if (type == mtpc_messageActionPollAppendAnswer) {
const auto &data = action.c_messageActionPollAppendAnswer();
UpdateComponents(HistoryServicePollAppendAnswer::Bit());
const auto append = Get<HistoryServicePollAppendAnswer>();
data.vanswer().match([&](const MTPDpollAnswer &answer) {
append->answer.option = answer.voption().v;
append->answer.text = Api::ParseTextWithEntities(
&_history->session(),
answer.vtext());
}, [](const auto &) {
});
} else if (type == mtpc_messageActionPollDeleteAnswer) {
const auto &data = action.c_messageActionPollDeleteAnswer();
UpdateComponents(HistoryServicePollDeleteAnswer::Bit());
const auto del = Get<HistoryServicePollDeleteAnswer>();
data.vanswer().match([&](const MTPDpollAnswer &answer) {
del->answer.option = answer.voption().v;
del->answer.text = Api::ParseTextWithEntities(
&_history->session(),
answer.vtext());
}, [](const auto &) {
});
} else if (type == mtpc_messageActionSuggestedPostApproval) {
const auto &data = action.c_messageActionSuggestedPostApproval();
UpdateComponents(HistoryServiceSuggestDecision::Bit());
@@ -6577,6 +6609,14 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) {
return prepareTodoAppendTasksText();
};
auto preparePollAppendAnswer = [&](const MTPDmessageActionPollAppendAnswer &) {
return preparePollAppendAnswerText();
};
auto preparePollDeleteAnswer = [&](const MTPDmessageActionPollDeleteAnswer &) {
return preparePollDeleteAnswerText();
};
auto prepareSuggestedPostApproval = [&](const MTPDmessageActionSuggestedPostApproval &data) {
return PreparedServiceText{ { data.is_rejected()
? tr::lng_action_post_rejected(tr::now)
@@ -6863,6 +6903,7 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) {
prepareConferenceCall,
prepareTodoCompletions,
prepareTodoAppendTasks,
preparePollAppendAnswer,
prepareSuggestedPostApproval,
prepareSuggestedPostSuccess,
prepareSuggestedPostRefund,
@@ -6875,7 +6916,7 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) {
prepareNoForwardsRequest,
prepareManagedBotCreated,
PrepareEmptyText<MTPDmessageActionPollAppendAnswer>,
PrepareEmptyText<MTPDmessageActionPollDeleteAnswer>,
preparePollDeleteAnswer,
PrepareEmptyText<MTPDmessageActionRequestedPeerSentMe>,
PrepareErrorText<MTPDmessageActionEmpty>));
@@ -7661,6 +7702,58 @@ PreparedServiceText HistoryItem::prepareTodoAppendTasksText() {
return result;
}
PreparedServiceText HistoryItem::preparePollAppendAnswerText() {
const auto append = Get<HistoryServicePollAppendAnswer>();
const auto option = append
? append->answer.text.text
: QString();
if (out()) {
return {
tr::lng_action_poll_added_answer_self(
tr::now,
lt_option,
{ option },
tr::marked),
};
}
return {
.text = tr::lng_action_poll_added_answer(
tr::now,
lt_from,
fromLinkText(),
lt_option,
{ option },
tr::marked),
.links = { fromLink() },
};
}
PreparedServiceText HistoryItem::preparePollDeleteAnswerText() {
const auto del = Get<HistoryServicePollDeleteAnswer>();
const auto option = del
? del->answer.text.text
: QString();
if (out()) {
return {
tr::lng_action_poll_deleted_answer_self(
tr::now,
lt_option,
{ option },
tr::marked),
};
}
return {
.text = tr::lng_action_poll_deleted_answer(
tr::now,
lt_from,
fromLinkText(),
lt_option,
{ option },
tr::marked),
.links = { fromLink() },
};
}
TextWithEntities HistoryItem::fromLinkText() const {
return tr::link(st::wrap_rtl(_from->name()), 1);
}
@@ -711,6 +711,8 @@ private:
TimeId scheduleDate);
[[nodiscard]] PreparedServiceText prepareTodoCompletionsText();
[[nodiscard]] PreparedServiceText prepareTodoAppendTasksText();
[[nodiscard]] PreparedServiceText preparePollAppendAnswerText();
[[nodiscard]] PreparedServiceText preparePollDeleteAnswerText();
[[nodiscard]] PreparedServiceText composeTodoIncompleted(
not_null<HistoryServiceTodoCompletions*> done);
@@ -722,6 +722,18 @@ struct HistoryServiceTodoAppendTasks
[[nodiscard]] TextWithEntities ComposeTodoTasksList(
not_null<HistoryServiceTodoAppendTasks*> append);
struct HistoryServicePollAppendAnswer
: RuntimeComponent<HistoryServicePollAppendAnswer, HistoryItem>
, HistoryServiceDependentData {
PollAnswer answer;
};
struct HistoryServicePollDeleteAnswer
: RuntimeComponent<HistoryServicePollDeleteAnswer, HistoryItem>
, HistoryServiceDependentData {
PollAnswer answer;
};
struct HistoryServiceSuggestDecision
: RuntimeComponent<HistoryServiceSuggestDecision, HistoryItem>
, HistoryServiceDependentData {
@@ -823,6 +823,10 @@ TextState Service::textState(QPoint point, StateRequest request) const {
result.link = done->lnk;
} else if (const auto append = item->Get<HistoryServiceTodoAppendTasks>()) {
result.link = append->lnk;
} else if (const auto pollAppend = item->Get<HistoryServicePollAppendAnswer>()) {
result.link = pollAppend->lnk;
} else if (const auto pollDelete = item->Get<HistoryServicePollDeleteAnswer>()) {
result.link = pollDelete->lnk;
} else if (const auto finish = item->Get<HistoryServiceSuggestFinish>()) {
result.link = finish->lnk;
} else if (media && data()->showSimilarChannels()) {