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 {
fn markup() -> ReplyKeyboardMarkup {
ReplyKeyboardMarkup {
keyboard: vec![vec![
KeyboardButton {
text: "Rock".to_owned(),
request: None,
},
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,
}
ReplyKeyboardMarkup::default().append_row(vec![
KeyboardButton::new("Rock"),
KeyboardButton::new("Metal"),
KeyboardButton::new("Pop"),
KeyboardButton::new("Other"),
])
}
}
@ -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]
// ============================================================================
type Ctx = SessionHandlerCtx<Message, User>;
type Res = Result<SessionState<User>, RequestError>;
async fn send_favourite_music_types(ctx: &Ctx) -> Result<(), RequestError> {
ctx.bot
.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(())
}
type Ctx = SessionHandlerCtx<Message, User>;
type Res = Result<SessionState<User>, RequestError>;
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))
}
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());
Ok(SessionState::Next(ctx.session))
}
@ -114,7 +87,7 @@ async fn age(mut ctx: Ctx) -> Res {
send_favourite_music_types(&ctx).await?;
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))
@ -124,11 +97,11 @@ async fn favourite_music(mut ctx: Ctx) -> Res {
match ctx.update.text().unwrap().parse() {
Ok(ok) => {
ctx.session.favourite_music = Some(ok);
reply!(ctx, format!("Fine. {}", ctx.session));
ctx.reply(format!("Fine. {}", ctx.session)).await?;
Ok(SessionState::Exit)
}
Err(_) => {
reply!(ctx, "Oh, please, enter from the keyboard!");
ctx.reply("Oh, please, enter from the keyboard!").await?;
Ok(SessionState::Next(ctx.session))
}
}

View file

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

View file

@ -24,6 +24,28 @@ pub struct KeyboardButton {
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
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum ButtonRequest {

View file

@ -10,7 +10,7 @@ use crate::types::KeyboardButton;
/// [custom keyboard]: https://core.telegram.org/bots#keyboards
/// [Introduction to bots]: https://core.telegram.org/bots#keyboards
#[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 {
/// Array of button rows, each represented by an Array of
/// [`KeyboardButton`] objects
@ -43,3 +43,46 @@ pub struct ReplyKeyboardMarkup {
/// [`Message`]: crate::types::Message
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
}
}