Simplify building ReplyKeyboardMarkup

This commit is contained in:
Temirkhan Myrzamadi 2020-02-03 00:54:11 +06:00
parent f436a0269b
commit 2c4102e2b3
4 changed files with 81 additions and 47 deletions

View file

@ -21,29 +21,12 @@ enum FavouriteMusic {
impl FavouriteMusic { impl FavouriteMusic {
fn markup() -> ReplyKeyboardMarkup { fn markup() -> ReplyKeyboardMarkup {
ReplyKeyboardMarkup { ReplyKeyboardMarkup::default().append_row(vec![
keyboard: vec![vec![ KeyboardButton::new("Rock"),
KeyboardButton { KeyboardButton::new("Metal"),
text: "Rock".to_owned(), KeyboardButton::new("Pop"),
request: None, KeyboardButton::new("Other"),
}, ])
KeyboardButton {
text: "Metal".to_owned(),
request: None,
},
KeyboardButton {
text: "Pop".to_owned(),
request: None,
},
KeyboardButton {
text: "Other".to_owned(),
request: None,
},
]],
resize_keyboard: None,
one_time_keyboard: None,
selective: None,
}
} }
} }
@ -70,21 +53,13 @@ impl Display for User {
} }
} }
// ============================================================================
// [Some macros]
// ============================================================================
#[macro_export]
macro_rules! reply {
($ctx:ident, $text:expr) => {
$ctx.reply($text).await?;
};
}
// ============================================================================ // ============================================================================
// [Control our FSM] // [Control our FSM]
// ============================================================================ // ============================================================================
type Ctx = SessionHandlerCtx<Message, User>;
type Res = Result<SessionState<User>, RequestError>;
async fn send_favourite_music_types(ctx: &Ctx) -> Result<(), RequestError> { async fn send_favourite_music_types(ctx: &Ctx) -> Result<(), RequestError> {
ctx.bot ctx.bot
.send_message(ctx.chat_id(), "Good. Now choose your favourite music:") .send_message(ctx.chat_id(), "Good. Now choose your favourite music:")
@ -94,16 +69,14 @@ async fn send_favourite_music_types(ctx: &Ctx) -> Result<(), RequestError> {
Ok(()) Ok(())
} }
type Ctx = SessionHandlerCtx<Message, User>;
type Res = Result<SessionState<User>, RequestError>;
async fn start(ctx: Ctx) -> Res { async fn start(ctx: Ctx) -> Res {
reply!(ctx, "Let's start! First, what's your full name?"); ctx.reply("Let's start! First, what's your full name?")
.await?;
Ok(SessionState::Next(ctx.session)) Ok(SessionState::Next(ctx.session))
} }
async fn full_name(mut ctx: Ctx) -> Res { async fn full_name(mut ctx: Ctx) -> Res {
reply!(ctx, "What a wonderful name! Your age?"); ctx.reply("What a wonderful name! Your age?").await?;
ctx.session.full_name = Some(ctx.update.text().unwrap().to_owned()); ctx.session.full_name = Some(ctx.update.text().unwrap().to_owned());
Ok(SessionState::Next(ctx.session)) Ok(SessionState::Next(ctx.session))
} }
@ -114,7 +87,7 @@ async fn age(mut ctx: Ctx) -> Res {
send_favourite_music_types(&ctx).await?; send_favourite_music_types(&ctx).await?;
ctx.session.age = Some(ok); ctx.session.age = Some(ok);
} }
Err(_) => reply!(ctx, "Oh, please, enter a number!"), Err(_) => ctx.reply("Oh, please, enter a number!").await?,
} }
Ok(SessionState::Next(ctx.session)) Ok(SessionState::Next(ctx.session))
@ -124,11 +97,11 @@ async fn favourite_music(mut ctx: Ctx) -> Res {
match ctx.update.text().unwrap().parse() { match ctx.update.text().unwrap().parse() {
Ok(ok) => { Ok(ok) => {
ctx.session.favourite_music = Some(ok); ctx.session.favourite_music = Some(ok);
reply!(ctx, format!("Fine. {}", ctx.session)); ctx.reply(format!("Fine. {}", ctx.session)).await?;
Ok(SessionState::Exit) Ok(SessionState::Exit)
} }
Err(_) => { Err(_) => {
reply!(ctx, "Oh, please, enter from the keyboard!"); ctx.reply("Oh, please, enter from the keyboard!").await?;
Ok(SessionState::Next(ctx.session)) Ok(SessionState::Next(ctx.session))
} }
} }

View file

@ -33,10 +33,6 @@ pub struct InlineKeyboardMarkup {
/// let keyboard = InlineKeyboardMarkup::new().append_row(vec![url_button]); /// let keyboard = InlineKeyboardMarkup::new().append_row(vec![url_button]);
/// ``` /// ```
impl InlineKeyboardMarkup { impl InlineKeyboardMarkup {
pub fn new() -> Self {
<_>::default()
}
pub fn append_row(mut self, buttons: Vec<InlineKeyboardButton>) -> Self { pub fn append_row(mut self, buttons: Vec<InlineKeyboardButton>) -> Self {
self.inline_keyboard.push(buttons); self.inline_keyboard.push(buttons);
self self

View file

@ -24,6 +24,28 @@ pub struct KeyboardButton {
pub request: Option<ButtonRequest>, pub request: Option<ButtonRequest>,
} }
impl KeyboardButton {
/// Creates `KeyboardButton` with the provided `text` and all the other
/// fields set to `None`.
pub fn new<T>(text: T) -> Self
where
T: Into<String>,
{
Self {
text: text.into(),
request: None,
}
}
pub fn request<T>(mut self, val: T) -> Self
where
T: Into<Option<ButtonRequest>>,
{
self.request = val.into();
self
}
}
// Serialize + Deserialize are implemented by hand // Serialize + Deserialize are implemented by hand
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum ButtonRequest { pub enum ButtonRequest {

View file

@ -10,7 +10,7 @@ use crate::types::KeyboardButton;
/// [custom keyboard]: https://core.telegram.org/bots#keyboards /// [custom keyboard]: https://core.telegram.org/bots#keyboards
/// [Introduction to bots]: https://core.telegram.org/bots#keyboards /// [Introduction to bots]: https://core.telegram.org/bots#keyboards
#[serde_with_macros::skip_serializing_none] #[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, Default)]
pub struct ReplyKeyboardMarkup { pub struct ReplyKeyboardMarkup {
/// Array of button rows, each represented by an Array of /// Array of button rows, each represented by an Array of
/// [`KeyboardButton`] objects /// [`KeyboardButton`] objects
@ -43,3 +43,46 @@ pub struct ReplyKeyboardMarkup {
/// [`Message`]: crate::types::Message /// [`Message`]: crate::types::Message
pub selective: Option<bool>, pub selective: Option<bool>,
} }
impl ReplyKeyboardMarkup {
pub fn append_row(mut self, buttons: Vec<KeyboardButton>) -> Self {
self.keyboard.push(buttons);
self
}
pub fn append_to_row(
mut self,
button: KeyboardButton,
index: usize,
) -> Self {
match self.keyboard.get_mut(index) {
Some(buttons) => buttons.push(button),
None => self.keyboard.push(vec![button]),
};
self
}
pub fn resize_keyboard<T>(mut self, val: T) -> Self
where
T: Into<Option<bool>>,
{
self.resize_keyboard = val.into();
self
}
pub fn one_time_keyboard<T>(mut self, val: T) -> Self
where
T: Into<Option<bool>>,
{
self.one_time_keyboard = val.into();
self
}
pub fn selective<T>(mut self, val: T) -> Self
where
T: Into<Option<bool>>,
{
self.selective = val.into();
self
}
}