Skip to content

Commit

Permalink
Reactions, consistent method naming and doc changes (#257)
Browse files Browse the repository at this point in the history
  • Loading branch information
dimentyy authored Aug 13, 2024
1 parent dbdd88c commit 8e215c0
Show file tree
Hide file tree
Showing 8 changed files with 191 additions and 16 deletions.
2 changes: 1 addition & 1 deletion lib/grammers-client/examples/echo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ async fn async_main() -> Result {
// This code uses `select` on Ctrl+C to gracefully stop the client and have a chance to
// save the session. You could have fancier logic to save the session if you wanted to
// (or even save it on every update). Or you could also ignore Ctrl+C and just use
// `while let Some(updates) = client.next_updates().await?`.
// `let update = client.next_update().await?`.
//
// Using `tokio::select!` would be a lot cleaner but add a heavy dependency,
// so a manual `select` is used instead by pinning async blocks by hand.
Expand Down
5 changes: 3 additions & 2 deletions lib/grammers-client/src/client/bots.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,18 +160,19 @@ impl Client {
) -> Result<bool, InvocationError> {
let message: InputMessage = input_message.into();
let entities = parse_mention_entities(self, message.entities);
let dc_id = message_id.dc_id();
let result = self
.invoke_in_dc(
&tl::functions::messages::EditInlineBotMessage {
id: message_id.clone(),
id: message_id,
message: Some(message.text),
media: message.media,
entities,
no_webpage: !message.link_preview,
reply_markup: message.reply_markup,
invert_media: message.invert_media,
},
message_id.dc_id(),
dc_id,
)
.await?;
Ok(result)
Expand Down
53 changes: 51 additions & 2 deletions lib/grammers-client/src/client/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@
// except according to those terms.

//! Methods related to sending messages.
use crate::types::{IterBuffer, Message};
use crate::types::{InputReactions, IterBuffer, Message};
use crate::utils::{generate_random_id, generate_random_ids};
use crate::{types, ChatMap, Client};
use chrono::{DateTime, FixedOffset};
pub use grammers_mtsender::{AuthorizationError, InvocationError};
use grammers_session::PackedChat;
use grammers_tl_types as tl;
use grammers_tl_types::enums::InputPeer;
use std::collections::HashMap;
use tl::enums::InputPeer;
use tl::functions::messages::SendReaction;

fn get_message_id(message: &tl::enums::Message) -> i32 {
match message {
Expand Down Expand Up @@ -1024,4 +1025,52 @@ impl Client {
.await?;
Ok(())
}

/// Send reaction.
///
/// # Examples
///
/// Via emoticon
///
/// ```
/// # async fn f(chat: grammers_client::types::Chat, client: grammers_client::Client) -> Result<(), Box<dyn std::error::Error>> {
/// let message_id = 123;
///
/// client.send_reaction(&chat, message_id, "👍").await?;
/// # Ok(())
/// # }
/// ```
///
/// Make animation big & Add to recent
///
/// ```
/// # async fn f(chat: grammers_client::types::Chat, client: grammers_client::Client) -> Result<(), Box<dyn std::error::Error>> {
/// use grammers_client::types::InputReactions;
///
/// let message_id = 123;
/// let reactions = InputReactions::emoticon("🤯").big().add_to_recent();
///
/// client.send_reaction(&chat, message_id, reactions).await?;
/// # Ok(())
/// # }
/// ```
pub async fn send_reaction<C: Into<PackedChat>, R: Into<InputReactions>>(
&self,
chat: C,
message_id: i32,
reactions: R,
) -> Result<(), InvocationError> {
let reactions = reactions.into();

self.invoke(&SendReaction {
big: reactions.big,
add_to_recent: reactions.add_to_recent,
peer: chat.into().to_input_peer(),
msg_id: message_id,
reaction: Some(reactions.reactions),
})
.await?;

Ok(())
}
}
7 changes: 4 additions & 3 deletions lib/grammers-client/src/types/inline/send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use grammers_tl_types as tl;
use std::fmt;
use std::sync::Arc;

/// Represents an update of user choosing the result of inline query and sending it to their chat partner.
#[derive(Clone)]
pub struct InlineSend {
raw: tl::types::UpdateBotInlineSend,
Expand Down Expand Up @@ -63,14 +64,14 @@ impl InlineSend {
/// Identifier of sent inline message.
/// Available only if there is an inline keyboard attached.
/// Will be also received in callback queries and can be used to edit the message.
pub fn msg_id(&self) -> Option<tl::enums::InputBotInlineMessageId> {
pub fn message_id(&self) -> Option<tl::enums::InputBotInlineMessageId> {
self.raw.msg_id.clone()
}

/// Edits this inline message.
///
/// **This method will return Ok(None) if message id is None (e.g. if an inline keyboard is not attached)**
pub async fn edit_msg(
pub async fn edit_message(
&self,
input_message: impl Into<InputMessage>,
) -> Result<Option<bool>, InvocationError> {
Expand All @@ -93,7 +94,7 @@ impl fmt::Debug for InlineSend {
.field("text", &self.text())
.field("sender", &self.sender())
.field("result_id", &self.result_id())
.field("msg_id", &self.msg_id())
.field("message_id", &self.message_id())
.finish()
}
}
36 changes: 35 additions & 1 deletion lib/grammers-client/src/types/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
// except according to those terms.
#[cfg(any(feature = "markdown", feature = "html"))]
use crate::parsers;
use crate::types::reactions::InputReactions;
use crate::types::{Downloadable, InputMessage, Media, Photo};
use crate::utils;
use crate::ChatMap;
Expand Down Expand Up @@ -123,7 +124,7 @@ impl Message {
edit_hide: false,
pinned: false,
noforwards: false, // TODO true if channel has noforwads?
invert_media: false,
invert_media: input.invert_media,
id: updates.id,
from_id: None, // TODO self
from_boosts_applied: None,
Expand Down Expand Up @@ -377,6 +378,39 @@ impl Message {
}
}

/// React to this message.
///
/// # Examples
///
/// ```
/// # async fn f(message: grammers_client::types::Message, client: grammers_client::Client) -> Result<(), Box<dyn std::error::Error>> {
/// message.react("👍").await?;
/// # Ok(())
/// # }
/// ```
///
/// Make animation big & Add to recent
///
/// ```
/// # async fn f(message: grammers_client::types::Message, client: grammers_client::Client) -> Result<(), Box<dyn std::error::Error>> {
/// use grammers_client::types::InputReactions;
///
/// let reactions = InputReactions::emoticon("🤯").big().add_to_recent();
///
/// message.react(reactions).await?;
/// # Ok(())
/// # }
/// ```
pub async fn react<R: Into<InputReactions>>(
&self,
reactions: R,
) -> Result<(), InvocationError> {
self.client
.send_reaction(self.chat(), self.id(), reactions)
.await?;
Ok(())
}

/// How many reactions does this message have, when applicable.
pub fn reaction_count(&self) -> Option<i32> {
match &self.raw.reactions {
Expand Down
2 changes: 2 additions & 0 deletions lib/grammers-client/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub mod participant;
pub mod password_token;
pub mod permissions;
pub mod photo_sizes;
pub mod reactions;
pub mod reply_markup;
pub mod terms_of_service;
pub mod update;
Expand All @@ -53,6 +54,7 @@ pub use message_deletion::MessageDeletion;
pub use participant::{Participant, Role};
pub use password_token::PasswordToken;
pub use permissions::{Permissions, Restrictions};
pub use reactions::InputReactions;
pub(crate) use reply_markup::ReplyMarkup;
pub use terms_of_service::TermsOfService;
pub use update::Update;
91 changes: 91 additions & 0 deletions lib/grammers-client/src/types/reactions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright 2020 - developers of the `grammers` project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use grammers_tl_types as tl;
use tl::enums::Reaction;

#[derive(Clone, Debug)]
pub struct InputReactions {
pub(crate) reactions: Vec<Reaction>,
pub(crate) add_to_recent: bool,
pub(crate) big: bool,
}

impl InputReactions {
/// Make reaction animation big.
pub fn big(mut self) -> Self {
self.big = true;
self
}

/// Add this reaction to the recent reactions list.
///
/// More about that: \
/// https://core.telegram.org/api/reactions#recent-reactions
pub fn add_to_recent(mut self) -> Self {
self.add_to_recent = true;
self
}

/// Create new InputReactions with one emoticon reaction
pub fn emoticon<S: Into<String>>(emoticon: S) -> Self {
Self {
reactions: vec![Reaction::Emoji(tl::types::ReactionEmoji {
emoticon: emoticon.into(),
})],
..Self::default()
}
}

/// Create new InputReactions with one custom emoji reaction
pub fn custom_emoji(document_id: i64) -> Self {
Self {
reactions: vec![Reaction::CustomEmoji(tl::types::ReactionCustomEmoji {
document_id,
})],
..Self::default()
}
}
}

impl Default for InputReactions {
fn default() -> Self {
Self {
reactions: vec![],
add_to_recent: false,
big: false,
}
}
}

impl Into<InputReactions> for String {
fn into(self) -> InputReactions {
InputReactions::emoticon(self)
}
}

impl Into<InputReactions> for &str {
fn into(self) -> InputReactions {
InputReactions::emoticon(self)
}
}

impl From<Vec<Reaction>> for InputReactions {
fn from(reactions: Vec<Reaction>) -> Self {
Self {
reactions,
..Self::default()
}
}
}

impl Into<Vec<Reaction>> for InputReactions {
fn into(self) -> Vec<Reaction> {
return self.reactions;
}
}
11 changes: 4 additions & 7 deletions lib/grammers-client/src/types/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

use std::sync::Arc;

use super::{inline::send::InlineSend, CallbackQuery, ChatMap, InlineQuery, Message};
use super::{CallbackQuery, ChatMap, InlineQuery, InlineSend, Message};
use crate::{types::MessageDeletion, Client};
use grammers_tl_types as tl;

Expand All @@ -27,7 +27,7 @@ pub enum Update {
/// Occurs whenever you sign in as a bot and a user sends an inline query
/// such as `@bot query`.
InlineQuery(InlineQuery),
/// Occurs whenever you sign in as a bot and a user chooses result from an inline query answer.
/// Represents an update of user choosing the result of inline query and sending it to their chat partner.
InlineSend(InlineSend),
/// Raw events are not actual events.
/// Instead, they are the raw Update object that Telegram sends. You
Expand All @@ -40,11 +40,8 @@ pub enum Update {
}

impl Update {
pub(crate) fn new(
client: &Client,
update: tl::enums::Update,
chats: &Arc<ChatMap>,
) -> Option<Self> {
/// Create new friendly to use Update from its raw version and chat map
pub fn new(client: &Client, update: tl::enums::Update, chats: &Arc<ChatMap>) -> Option<Self> {
match update {
// NewMessage
tl::enums::Update::NewMessage(tl::types::UpdateNewMessage { message, .. }) => {
Expand Down

0 comments on commit 8e215c0

Please sign in to comment.