Add Message.unread_reactions.

This commit is contained in:
levlam 2022-01-28 17:10:17 +03:00
parent cab16967d0
commit e5084491f6
6 changed files with 164 additions and 17 deletions

View File

@ -786,6 +786,12 @@ messageReaction reaction:string total_count:int32 is_chosen:Bool recent_sender_i
//@reactions The list of reactions added to the message
messageInteractionInfo view_count:int32 forward_count:int32 reply_info:messageReplyInfo reactions:vector<messageReaction> = MessageInteractionInfo;
//@description Contains information about an unread reaction to a message
//@reaction Text representation of the reaction
//@sender_id Identifier of the sender, added the reaction
//@is_big True, if the reaction was added with a big animation
unreadReaction reaction:string sender_id:MessageSender is_big:Bool = UnreadReaction;
//@class MessageSendingState @description Contains information about the sending state of the message
@ -824,6 +830,7 @@ messageSendingStateFailed error_code:int32 error_message:string can_retry:Bool n
//@edit_date Point in time (Unix timestamp) when the message was last edited
//@forward_info Information about the initial message sender; may be null
//@interaction_info Information about interactions with the message; may be null
//@unread_reactions Information about unread reactions added to the message
//@reply_in_chat_id If non-zero, the identifier of the chat to which the replied message belongs; Currently, only messages in the Replies chat can have different reply_in_chat_id and chat_id
//@reply_to_message_id If non-zero, the identifier of the message this message is replying to; can be the identifier of a deleted message
//@message_thread_id If non-zero, the identifier of the message thread the message belongs to; unique within the chat to which the message belongs
@ -835,7 +842,7 @@ messageSendingStateFailed error_code:int32 error_message:string can_retry:Bool n
//@restriction_reason If non-empty, contains a human-readable description of the reason why access to this message must be restricted
//@content Content of the message
//@reply_markup Reply markup for the message; may be null
message id:int53 sender_id:MessageSender chat_id:int53 sending_state:MessageSendingState scheduling_state:MessageSchedulingState is_outgoing:Bool is_pinned:Bool can_be_edited:Bool can_be_forwarded:Bool can_be_saved:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_get_added_reactions:Bool can_get_statistics:Bool can_get_message_thread:Bool can_get_viewers:Bool can_get_media_timestamp_links:Bool has_timestamped_media:Bool is_channel_post:Bool contains_unread_mention:Bool date:int32 edit_date:int32 forward_info:messageForwardInfo interaction_info:messageInteractionInfo reply_in_chat_id:int53 reply_to_message_id:int53 message_thread_id:int53 ttl:int32 ttl_expires_in:double via_bot_user_id:int53 author_signature:string media_album_id:int64 restriction_reason:string content:MessageContent reply_markup:ReplyMarkup = Message;
message id:int53 sender_id:MessageSender chat_id:int53 sending_state:MessageSendingState scheduling_state:MessageSchedulingState is_outgoing:Bool is_pinned:Bool can_be_edited:Bool can_be_forwarded:Bool can_be_saved:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_get_added_reactions:Bool can_get_statistics:Bool can_get_message_thread:Bool can_get_viewers:Bool can_get_media_timestamp_links:Bool has_timestamped_media:Bool is_channel_post:Bool contains_unread_mention:Bool date:int32 edit_date:int32 forward_info:messageForwardInfo interaction_info:messageInteractionInfo unread_reactions:vector<unreadReaction> reply_in_chat_id:int53 reply_to_message_id:int53 message_thread_id:int53 ttl:int32 ttl_expires_in:double via_bot_user_id:int53 author_signature:string media_album_id:int64 restriction_reason:string content:MessageContent reply_markup:ReplyMarkup = Message;
//@description Contains a list of messages @total_count Approximate total count of messages found @messages List of messages; messages may be null
messages total_count:int32 messages:vector<message> = Messages;
@ -1006,6 +1013,7 @@ videoChat group_call_id:int32 has_participants:Bool default_participant_id:Messa
//@last_read_inbox_message_id Identifier of the last read incoming message
//@last_read_outbox_message_id Identifier of the last read outgoing message
//@unread_mention_count Number of unread messages with a mention/reply in the chat
//@unread_reaction_count Number of messages with unread reactions in the chat
//@notification_settings Notification settings for the chat
//@available_reactions List of reactions, available in the chat
//@message_ttl Current message Time To Live setting (self-destruct timer) for the chat; 0 if not defined. TTL is counted from the time message or its content is viewed in secret chats and from the send date in other chats
@ -1016,7 +1024,7 @@ videoChat group_call_id:int32 has_participants:Bool default_participant_id:Messa
//@reply_markup_message_id Identifier of the message from which reply markup needs to be used; 0 if there is no default custom reply markup in the chat
//@draft_message A draft of a message in the chat; may be null
//@client_data Application-specific data associated with the chat. (For example, the chat scroll position or local chat notification settings can be stored here.) Persistent if the message database is used
chat id:int53 type:ChatType title:string photo:chatPhotoInfo permissions:chatPermissions last_message:message positions:vector<chatPosition> message_sender_id:MessageSender has_protected_content:Bool is_marked_as_unread:Bool is_blocked:Bool has_scheduled_messages:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 notification_settings:chatNotificationSettings available_reactions:vector<string> message_ttl:int32 theme_name:string action_bar:ChatActionBar video_chat:videoChat pending_join_requests:chatJoinRequestsInfo reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat;
chat id:int53 type:ChatType title:string photo:chatPhotoInfo permissions:chatPermissions last_message:message positions:vector<chatPosition> message_sender_id:MessageSender has_protected_content:Bool is_marked_as_unread:Bool is_blocked:Bool has_scheduled_messages:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 unread_reaction_count:int32 notification_settings:chatNotificationSettings available_reactions:vector<string> message_ttl:int32 theme_name:string action_bar:ChatActionBar video_chat:videoChat pending_join_requests:chatJoinRequestsInfo reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat;
//@description Represents a list of chats @total_count Approximate total count of chats found @chat_ids List of chat identifiers
chats total_count:int32 chat_ids:vector<int53> = Chats;
@ -3753,6 +3761,9 @@ updateMessageContentOpened chat_id:int53 message_id:int53 = Update;
//@description A message with an unread mention was read @chat_id Chat identifier @message_id Message identifier @unread_mention_count The new number of unread mention messages left in the chat
updateMessageMentionRead chat_id:int53 message_id:int53 unread_mention_count:int32 = Update;
//@description The list of unread reactions added to a message was changed @chat_id Chat identifier @message_id Message identifier @unread_reactions The new list of unread reactions @unread_reaction_count The new number of messages with unread reactions left in the chat
updateMessageUnreadReactions chat_id:int53 message_id:int53 unread_reactions:vector<unreadReaction> unread_reaction_count:int32 = Update;
//@description A message with a live location was viewed. When the update is received, the application is supposed to update the live location
//@chat_id Identifier of the chat with the live location message @message_id Identifier of the message with live location
updateMessageLiveLocationViewed chat_id:int53 message_id:int53 = Update;
@ -3812,6 +3823,9 @@ updateChatTheme chat_id:int53 theme_name:string = Update;
//@description The chat unread_mention_count has changed @chat_id Chat identifier @unread_mention_count The number of unread mention messages left in the chat
updateChatUnreadMentionCount chat_id:int53 unread_mention_count:int32 = Update;
//@description The chat unread_reaction_count has changed @chat_id Chat identifier @unread_reaction_count The number of messages with unread reactions left in the chat
updateChatUnreadReactionCount chat_id:int53 unread_reaction_count:int32 = Update;
//@description A chat video chat state has changed @chat_id Chat identifier @video_chat New value of video_chat
updateChatVideoChat chat_id:int53 video_chat:videoChat = Update;

View File

@ -239,6 +239,23 @@ StringBuilder &operator<<(StringBuilder &string_builder, const MessageReaction &
return string_builder << ']';
}
td_api::object_ptr<td_api::unreadReaction> UnreadMessageReaction::get_unread_reaction_object(Td *td) const {
auto sender_id = get_min_message_sender_object(td, sender_dialog_id_, "get_unread_reaction_object");
if (sender_id == nullptr) {
return nullptr;
}
return td_api::make_object<td_api::unreadReaction>(reaction_, std::move(sender_id), is_big_);
}
bool operator==(const UnreadMessageReaction &lhs, const UnreadMessageReaction &rhs) {
return lhs.reaction_ == rhs.reaction_ && lhs.sender_dialog_id_ == rhs.sender_dialog_id_ && lhs.is_big_ == rhs.is_big_;
}
StringBuilder &operator<<(StringBuilder &string_builder, const UnreadMessageReaction &unread_reaction) {
return string_builder << '[' << unread_reaction.reaction_ << (unread_reaction.is_big_ ? " BY " : " by ")
<< unread_reaction.sender_dialog_id_ << ']';
}
unique_ptr<MessageReactions> MessageReactions::get_message_reactions(
Td *td, tl_object_ptr<telegram_api::messageReactions> &&reactions, bool is_bot) {
if (reactions == nullptr || is_bot) {
@ -299,6 +316,9 @@ unique_ptr<MessageReactions> MessageReactions::get_message_reactions(
}
recent_chooser_dialog_ids.push_back(dialog_id);
if (peer_reaction->unread_) {
result->unread_reactions_.emplace_back(std::move(peer_reaction->reaction_), dialog_id, peer_reaction->big_);
}
if (recent_chooser_dialog_ids.size() == MessageReaction::MAX_RECENT_CHOOSERS) {
break;
}
@ -384,13 +404,20 @@ bool MessageReactions::need_update_message_reactions(const MessageReactions *old
return true;
}
// has_pending_reaction_ doesn't affect visible state
// compare all other fields
// unread_reactions_ are updated independently; compare all other fields
return old_reactions->reactions_ != new_reactions->reactions_ || old_reactions->is_min_ != new_reactions->is_min_ ||
old_reactions->can_see_all_choosers_ != new_reactions->can_see_all_choosers_ ||
old_reactions->need_polling_ != new_reactions->need_polling_;
}
bool MessageReactions::need_update_unread_reactions(const MessageReactions *old_reactions,
const MessageReactions *new_reactions) {
if (old_reactions == nullptr || old_reactions->unread_reactions_.empty()) {
return !(new_reactions == nullptr || new_reactions->unread_reactions_.empty());
}
return new_reactions == nullptr || old_reactions->unread_reactions_ != new_reactions->unread_reactions_;
}
void reload_message_reactions(Td *td, DialogId dialog_id, vector<MessageId> &&message_ids) {
if (!td->messages_manager_->have_input_peer(dialog_id, AccessRights::Read) || message_ids.empty()) {
return;

View File

@ -93,10 +93,44 @@ inline bool operator!=(const MessageReaction &lhs, const MessageReaction &rhs) {
return !(lhs == rhs);
}
StringBuilder &operator<<(StringBuilder &string_builder, const MessageReaction &message_reaction);
StringBuilder &operator<<(StringBuilder &string_builder, const MessageReaction &reaction);
class UnreadMessageReaction {
string reaction_;
DialogId sender_dialog_id_;
bool is_big_ = false;
friend bool operator==(const UnreadMessageReaction &lhs, const UnreadMessageReaction &rhs);
friend StringBuilder &operator<<(StringBuilder &string_builder, const UnreadMessageReaction &message_reaction);
public:
UnreadMessageReaction() = default;
UnreadMessageReaction(string reaction, DialogId sender_dialog_id, bool is_big)
: reaction_(std::move(reaction)), sender_dialog_id_(sender_dialog_id), is_big_(is_big) {
}
td_api::object_ptr<td_api::unreadReaction> get_unread_reaction_object(Td *td) const;
template <class StorerT>
void store(StorerT &storer) const;
template <class ParserT>
void parse(ParserT &parser);
};
bool operator==(const UnreadMessageReaction &lhs, const UnreadMessageReaction &rhs);
inline bool operator!=(const UnreadMessageReaction &lhs, const UnreadMessageReaction &rhs) {
return !(lhs == rhs);
}
StringBuilder &operator<<(StringBuilder &string_builder, const UnreadMessageReaction &unread_reaction);
struct MessageReactions {
vector<MessageReaction> reactions_;
vector<UnreadMessageReaction> unread_reactions_;
bool is_min_ = false;
bool need_polling_ = true;
bool can_see_all_choosers_ = false;
@ -119,6 +153,9 @@ struct MessageReactions {
static bool need_update_message_reactions(const MessageReactions *old_reactions,
const MessageReactions *new_reactions);
static bool need_update_unread_reactions(const MessageReactions *old_reactions,
const MessageReactions *new_reactions);
template <class StorerT>
void store(StorerT &storer) const;

View File

@ -53,34 +53,60 @@ void MessageReaction::parse(ParserT &parser) {
CHECK(!is_empty());
}
template <class StorerT>
void UnreadMessageReaction::store(StorerT &storer) const {
BEGIN_STORE_FLAGS();
STORE_FLAG(is_big_);
END_STORE_FLAGS();
td::store(reaction_, storer);
td::store(sender_dialog_id_, storer);
}
template <class ParserT>
void UnreadMessageReaction::parse(ParserT &parser) {
BEGIN_PARSE_FLAGS();
PARSE_FLAG(is_big_);
END_PARSE_FLAGS();
td::parse(reaction_, parser);
td::parse(sender_dialog_id_, parser);
}
template <class StorerT>
void MessageReactions::store(StorerT &storer) const {
bool has_reactions = !reactions_.empty();
bool has_unread_reactions = !unread_reactions_.empty();
BEGIN_STORE_FLAGS();
STORE_FLAG(is_min_);
STORE_FLAG(need_polling_);
STORE_FLAG(can_see_all_choosers_);
STORE_FLAG(has_pending_reaction_);
STORE_FLAG(has_unread_reactions);
STORE_FLAG(has_reactions);
END_STORE_FLAGS();
if (has_reactions) {
td::store(reactions_, storer);
}
if (has_unread_reactions) {
td::store(unread_reactions_, storer);
}
}
template <class ParserT>
void MessageReactions::parse(ParserT &parser) {
bool has_reactions;
bool has_unread_reactions;
BEGIN_PARSE_FLAGS();
PARSE_FLAG(is_min_);
PARSE_FLAG(need_polling_);
PARSE_FLAG(can_see_all_choosers_);
PARSE_FLAG(has_pending_reaction_);
PARSE_FLAG(has_unread_reactions);
PARSE_FLAG(has_reactions);
END_PARSE_FLAGS();
if (has_reactions) {
td::parse(reactions_, parser);
}
if (has_unread_reactions) {
td::parse(unread_reactions_, parser);
}
}
} // namespace td

View File

@ -6996,6 +6996,20 @@ td_api::object_ptr<td_api::messageInteractionInfo> MessagesManager::get_message_
std::move(reactions));
}
vector<td_api::object_ptr<td_api::unreadReaction>> MessagesManager::get_unread_reactions_object(
DialogId dialog_id, const Message *m) const {
vector<td_api::object_ptr<td_api::unreadReaction>> unread_reactions;
if (is_visible_message_reactions(dialog_id, m) && m->reactions != nullptr) {
for (const auto &unread_reaction : m->reactions->unread_reactions_) {
auto unread_reaction_object = unread_reaction.get_unread_reaction_object(td_);
if (unread_reaction_object != nullptr) {
unread_reactions.push_back(std::move(unread_reaction_object));
}
}
}
return std::move(unread_reactions);
}
bool MessagesManager::update_message_interaction_info(DialogId dialog_id, Message *m, int32 view_count,
int32 forward_count, bool has_reply_info,
MessageReplyInfo &&reply_info, bool has_reactions,
@ -7017,16 +7031,18 @@ bool MessagesManager::update_message_interaction_info(DialogId dialog_id, Messag
}
}
}
if (has_reactions && reactions != nullptr && m->reactions != nullptr) {
reactions->update_from(*m->reactions);
}
if (has_reactions && reactions != nullptr) {
if (m->reactions != nullptr) {
reactions->update_from(*m->reactions);
}
reactions->sort(active_reaction_pos_);
}
bool need_update_reactions =
has_reactions && MessageReactions::need_update_message_reactions(m->reactions.get(), reactions.get());
bool need_update_unread_reactions =
has_reactions && MessageReactions::need_update_unread_reactions(m->reactions.get(), reactions.get());
if (view_count > m->view_count || forward_count > m->forward_count || need_update_reply_info ||
need_update_reactions) {
need_update_reactions || need_update_unread_reactions) {
LOG(DEBUG) << "Update interaction info of " << FullMessageId{dialog_id, m->message_id} << " from " << m->view_count
<< '/' << m->forward_count << "/" << m->reply_info << " to " << view_count << '/' << forward_count << "/"
<< reply_info;
@ -7053,9 +7069,14 @@ bool MessagesManager::update_message_interaction_info(DialogId dialog_id, Messag
}
need_update |= is_visible_message_reply_info(dialog_id, m);
}
if (need_update_reactions) {
if (need_update_reactions || need_update_unread_reactions) {
m->reactions = std::move(reactions);
need_update |= is_visible_message_reactions(dialog_id, m);
if (is_visible_message_reactions(dialog_id, m)) {
need_update |= need_update_reactions;
if (need_update_unread_reactions) {
send_update_message_unread_reactions(dialog_id, m);
}
}
}
if (need_update) {
send_update_message_interaction_info(dialog_id, m);
@ -8281,7 +8302,11 @@ void MessagesManager::update_dialog_message_reactions_visibility(const Dialog *d
for (auto message_id : message_ids) {
const auto *m = get_message(d, message_id);
CHECK(m != nullptr);
CHECK(m->reactions != nullptr);
send_update_message_interaction_info(d->dialog_id, m);
if (!m->reactions->unread_reactions_.empty()) {
send_update_message_unread_reactions(d->dialog_id, m);
}
}
}
@ -20775,7 +20800,7 @@ td_api::object_ptr<td_api::chat> MessagesManager::get_chat_object(const Dialog *
get_dialog_has_scheduled_messages(d), can_delete_for_self, can_delete_for_all_users,
can_report_dialog(d->dialog_id), d->notification_settings.silent_send_message,
d->server_unread_count + d->local_unread_count, d->last_read_inbox_message_id.get(),
d->last_read_outbox_message_id.get(), d->unread_mention_count,
d->last_read_outbox_message_id.get(), d->unread_mention_count, 0,
get_chat_notification_settings_object(&d->notification_settings), get_dialog_active_reactions(d),
d->message_ttl.get_message_ttl_object(), get_dialog_theme_name(d), get_chat_action_bar_object(d),
get_video_chat_object(d), get_chat_join_requests_info_object(d), d->reply_markup_message_id.get(),
@ -24121,6 +24146,7 @@ tl_object_ptr<td_api::message> MessagesManager::get_message_object(DialogId dial
auto scheduling_state = is_scheduled ? get_message_scheduling_state_object(m->date) : nullptr;
auto forward_info = get_message_forward_info_object(m->forward_info);
auto interaction_info = get_message_interaction_info_object(dialog_id, m);
auto unread_reactions = get_unread_reactions_object(dialog_id, m);
auto can_be_saved = can_save_message(dialog_id, m);
auto can_be_edited = for_event_log ? false : can_edit_message(dialog_id, m, false, td_->auth_manager_->is_bot());
auto can_be_forwarded = for_event_log ? false : can_forward_message(dialog_id, m) && can_be_saved;
@ -24153,9 +24179,10 @@ tl_object_ptr<td_api::message> MessagesManager::get_message_object(DialogId dial
is_outgoing, is_pinned, can_be_edited, can_be_forwarded, can_be_saved, can_delete_for_self,
can_delete_for_all_users, can_get_added_reactions, can_get_statistics, can_get_message_thread, can_get_viewers,
can_get_media_timestamp_links, has_timestamped_media, m->is_channel_post, contains_unread_mention, date,
edit_date, std::move(forward_info), std::move(interaction_info), reply_in_dialog_id.get(), reply_to_message_id,
top_thread_message_id, ttl, ttl_expires_in, via_bot_user_id, m->author_signature, media_album_id,
get_restriction_reason_description(m->restriction_reasons), std::move(content), std::move(reply_markup));
edit_date, std::move(forward_info), std::move(interaction_info), std::move(unread_reactions),
reply_in_dialog_id.get(), reply_to_message_id, top_thread_message_id, ttl, ttl_expires_in, via_bot_user_id,
m->author_signature, media_album_id, get_restriction_reason_description(m->restriction_reasons),
std::move(content), std::move(reply_markup));
}
tl_object_ptr<td_api::messages> MessagesManager::get_messages_object(int32 total_count, DialogId dialog_id,
@ -29765,6 +29792,17 @@ void MessagesManager::send_update_message_interaction_info(DialogId dialog_id, c
get_message_interaction_info_object(dialog_id, m)));
}
void MessagesManager::send_update_message_unread_reactions(DialogId dialog_id, const Message *m) const {
CHECK(m != nullptr);
if (td_->auth_manager_->is_bot() || !m->is_update_sent) {
return;
}
send_closure(G()->td(), &Td::send_update,
make_tl_object<td_api::updateMessageUnreadReactions>(dialog_id.get(), m->message_id.get(),
get_unread_reactions_object(dialog_id, m), 0));
}
void MessagesManager::send_update_message_live_location_viewed(FullMessageId full_message_id) {
CHECK(get_message(full_message_id) != nullptr);
send_closure(G()->td(), &Td::send_update,

View File

@ -2111,6 +2111,9 @@ class MessagesManager final : public Actor {
td_api::object_ptr<td_api::messageInteractionInfo> get_message_interaction_info_object(DialogId dialog_id,
const Message *m) const;
vector<td_api::object_ptr<td_api::unreadReaction>> get_unread_reactions_object(DialogId dialog_id,
const Message *m) const;
bool update_message_interaction_info(DialogId dialog_id, Message *m, int32 view_count, int32 forward_count,
bool has_reply_info, MessageReplyInfo &&reply_info, bool has_reactions,
unique_ptr<MessageReactions> &&reactions, const char *source);
@ -2387,6 +2390,8 @@ class MessagesManager final : public Actor {
void send_update_message_interaction_info(DialogId dialog_id, const Message *m) const;
void send_update_message_unread_reactions(DialogId dialog_id, const Message *m) const;
void send_update_message_live_location_viewed(FullMessageId full_message_id);
void send_update_delete_messages(DialogId dialog_id, vector<int64> &&message_ids, bool is_permanent,