Skip to content

Commit

Permalink
Complete Calendar widget schema
Browse files Browse the repository at this point in the history
  • Loading branch information
syrtcevvi committed Sep 7, 2024
1 parent ea9c763 commit 9daab71
Show file tree
Hide file tree
Showing 9 changed files with 178 additions and 136 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,26 @@ use syn::Path;
#[derive(Debug, FromField)]
#[darling(attributes(calendar))]
pub struct CalendarParameters {
/// CallbackQuery data prefix to be sent with the selected day
pub day_prefix: Option<String>,
/// Handler to be invoked when the day-button is clicked
#[darling(rename = "day_click")]
pub day_click_handler: Path,
/// CallbackQuery data prefix to be sent with the selected day
pub day_prefix: String,
/// CallbackQuery data prefix to be sent with the selected day of the week
pub weekday_prefix: Option<String>,
/// Handler to be invoked when the weekday-button is clicked
#[darling(rename = "weekday_click")]
pub weekday_click_handler: Option<Path>,
/// CallbackQuery data to be sent when the `previous year` button is
/// clicked, `py` by default
/// clicked
pub prev_year: Option<String>,
/// CallbackQuery data to be sent when the `next year` button is clicked,
/// `ny` by default
/// CallbackQuery data to be sent when the `next year` button is clicked
pub next_year: Option<String>,
/// CallbackQuery data to be sent when the `previous month` button is
/// clicked, `pm` by default
/// clicked
pub prev_month: Option<String>,
/// CallbackQuery data to be sent when the `next month` button is clicked,
/// `nm` by default
/// CallbackQuery data to be sent when the `next month` button is clicked
pub next_month: Option<String>,
/// CallbackQuery data for empty cells
pub noop_data: Option<String>,
}
10 changes: 10 additions & 0 deletions crates/teloxide-inline-widgets-macros/src/constants.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
pub const NOOP_DATA: &str = "noop";

pub mod calendar {
pub const DAY_PREFIX: &str = "d_";
pub const WEEKDAY_PREFIX: &str = "w_";

pub const PREV_YEAR: &str = "py";
pub const NEXT_YEAR: &str = "ny";
pub const PREV_MONTH: &str = "pm";
pub const NEXT_MONTH: &str = "nm";
}

pub const RADIO_LIST_TYPE: &str = "RadioList";
pub const CHECKBOX_LIST_TYPE: &str = "CheckboxList";
pub const BUTTON_TYPE: &str = "Button";
Expand Down
42 changes: 23 additions & 19 deletions crates/teloxide-inline-widgets-macros/src/inline_widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::{
},
constants::*,
inline_widget::impls::*,
schemes::CalendarSchemaTypes,
};

/// Arguments for the top-level `#[inline_widget]` struct attribute.
Expand Down Expand Up @@ -46,7 +47,6 @@ pub(crate) fn inline_widget_impl(input: TokenStream) -> TokenStream {
};

let mut widget_container_impls = quote! {};
let mut get_inner_widgets_impl = quote! {};
let mut schema_impl = quote! {
dptree::entry()
};
Expand Down Expand Up @@ -118,39 +118,43 @@ pub(crate) fn inline_widget_impl(input: TokenStream) -> TokenStream {
CALENDAR_TYPE => {
let parameters = &match CalendarParameters::from_field(field) {
Ok(mut parameters) => {
parameters.prev_year = parameters.prev_year.or(Some("py".to_owned()));
parameters.next_year = parameters.next_year.or(Some("ny".to_owned()));
parameters.prev_month = parameters.prev_month.or(Some("pm".to_owned()));
parameters.next_month = parameters.next_month.or(Some("nm".to_owned()));
parameters.day_prefix =
parameters.day_prefix.or(Some(calendar::DAY_PREFIX.to_owned()));
parameters.weekday_prefix = parameters
.weekday_prefix
.or(Some(calendar::WEEKDAY_PREFIX.to_owned()));
parameters.prev_year =
parameters.prev_year.or(Some(calendar::PREV_YEAR.to_owned()));
parameters.next_year =
parameters.next_year.or(Some(calendar::NEXT_YEAR.to_owned()));
parameters.prev_month =
parameters.prev_month.or(Some(calendar::PREV_MONTH.to_owned()));
parameters.next_month =
parameters.next_month.or(Some(calendar::NEXT_MONTH.to_owned()));
parameters.noop_data =
parameters.noop_data.or(Some(NOOP_DATA.to_owned()));
parameters
}
Err(err) => return TokenStream::from(err.write_errors()),
};
widget_container_impl(component_parameters, &mut widget_container_impls);
calendar_component_impl(
parameters,
&CalendarSchemaTypes {
bot_ty: bot_ty.clone(),
widget_ty: struct_ident.clone(),
dialogue_ty: dialogue_ty.clone().expect(
"There must be the dialogue type for the `Calendar` widget",
),
},
component_parameters,
&mut schema_impl,
&mut markups,
);
}
// User-defined types
_ => {
// How to properly do this?
// Maybe smth like this:
// pub trait GetInnerWidgets {
// fn inner_widgets(&self) -> Vec<(Vec<Ident>, Path)>;
// }
unimplemented!()
// schema_impl.extend(quote! {
// .branch(<#field_type>::schema())
// });
// markups.push(quote! {
// (
// self.#field_ident.inline_keyboard_markup(&
// styles), self.#field_ident.
// size() )
// });
}
}
}
Expand Down
35 changes: 20 additions & 15 deletions crates/teloxide-inline-widgets-macros/src/inline_widget/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use syn::{Ident, Type};

use crate::{attribute_parameters::*, constants::*, schemes::button_schema};
use crate::{
attribute_parameters::*,
schemes::{button_schema, calendar_schema, CalendarSchemaTypes},
};

pub struct ComponentParameters<'a> {
/// User-defined widget identifier
Expand Down Expand Up @@ -89,38 +92,40 @@ pub fn button_component_impl(
}

pub fn calendar_component_impl(
CalendarParameters {
parameters: &CalendarParameters,
schema_types: &CalendarSchemaTypes,
ComponentParameters { field_ident, .. }: &ComponentParameters,
schema_impl: &mut TokenStream2,
markups: &mut Vec<TokenStream2>,
) {
let CalendarParameters {
day_prefix,
day_click_handler,
weekday_prefix,
prev_year,
next_year,
prev_month,
next_month,
}: &CalendarParameters,
ComponentParameters { struct_ident, field_ident, field_type }: &ComponentParameters,
schema_impl: &mut TokenStream2,
markups: &mut Vec<TokenStream2>,
) {
// FIXME
noop_data,
..
} = &parameters;

let calendar_schema_parameters = quote! {
CalendarSchemaParameters {
day_prefix: #day_prefix,
weekday_prefix: #weekday_prefix,
previous_year_data: #prev_year,
next_year_data: #next_year,
previous_month_data: #prev_month,
next_month_data: #next_month,
noop_data: #NOOP_DATA,
day_prefix: "d_",
weekday_prefix: "w_"
noop_data: #noop_data,
}
};

schema_impl.extend(quote! {
.branch(<#field_type>::schema::<#struct_ident>(&#calendar_schema_parameters))
});
markups.push(quote! {
(
self.#field_ident.inline_keyboard_markup(&#calendar_schema_parameters, &styles),
self.#field_ident.size()
)
});
schema_impl.extend(calendar_schema(schema_types, parameters));
}
6 changes: 5 additions & 1 deletion crates/teloxide-inline-widgets-macros/src/schemes.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
mod button;
mod calendar;

pub use self::button::button_schema;
pub use self::{
button::button_schema,
calendar::{calendar_schema, CalendarSchemaTypes},
};
93 changes: 93 additions & 0 deletions crates/teloxide-inline-widgets-macros/src/schemes/calendar.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use syn::{Ident, Path};

use crate::attribute_parameters::CalendarParameters;

pub struct CalendarSchemaTypes {
pub widget_ty: Ident,
pub bot_ty: Path,
pub dialogue_ty: Path,
}

/// Handler schema for the [`Calendar`] widget
pub fn calendar_schema(
CalendarSchemaTypes { widget_ty, bot_ty, dialogue_ty }: &CalendarSchemaTypes,
CalendarParameters {
day_click_handler,
day_prefix,
weekday_prefix,
weekday_click_handler,
prev_month,
next_month,
prev_year,
next_year,
noop_data,
}: &CalendarParameters,
) -> TokenStream2 {
let weekday_click_handler = if let Some(weekday_click_handler) = weekday_click_handler {
quote! {
.branch(
dptree::filter_map(|CallbackQueryData(cq_data): CallbackQueryData| {
Weekday::try_from(
cq_data.strip_prefix(#weekday_prefix)?.parse::<u8>().ok()?
).ok()
})
.endpoint(#weekday_click_handler)
)
}
} else {
quote! {}
};

quote! {
.branch(
dptree::entry()
.filter_map(|cq: CallbackQuery| cq.data.map(|data| CallbackQueryData(data)))
.branch(
dptree::filter_map(|CallbackQueryData(cq_data): CallbackQueryData| {
NaiveDate::parse_from_str(
cq_data.strip_prefix(#day_prefix)?,
"%Y/%m/%d",
)
.ok()
})
.endpoint(#day_click_handler)
)
#weekday_click_handler
.filter_map(|cq: CallbackQuery| cq.message.map(|msg| (msg.chat.id, msg.id, cq.id)))
.endpoint(
|
mut widget: #widget_ty,
bot: #bot_ty,
dialogue: #dialogue_ty,
(chat_id, message_id, cq_id): (ChatId, MessageId, String),
CallbackQueryData(cq_data): CallbackQueryData,
widget_styles: WidgetStyles
| async move {
bot.answer_callback_query(cq_id).await?;

if cq_data == #noop_data {
// TODO possibly custom notification here?
return Ok(())
}

let calendar = widget.get_widget();
match cq_data.as_str() {
#prev_year => calendar.set_previous_year(),
#next_year => calendar.set_next_year(),
#prev_month => calendar.set_previous_month(),
#next_month => calendar.set_next_month(),
_ => {
log::warn!("`Calendar` widget received strange `CallbackQuery::data`: \"{cq_data}\"");
}
}
widget.redraw(&bot, chat_id, message_id, &widget_styles).await?;
widget.update_state(&dialogue).await?;

Ok(())
},
),
)
}
}
9 changes: 6 additions & 3 deletions crates/teloxide-inline-widgets/src/prelude.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
pub use chrono::{NaiveDate, Weekday};
pub use log;
pub use teloxide::types::{CallbackQuery, MessageId};
pub use teloxide_inline_widgets_macros::InlineWidget;

pub use crate::{
layout::{Layout, LayoutOrientation},
traits::{GetSize, InlineWidget, WidgetContainer},
types::{Size, WidgetStyles},
types::{CallbackQueryData, Size, WidgetStyles},
widgets::{CalendarSchemaParameters, CheckboxListSchemaParameters, RadioListSchemaParameters},
};

pub use teloxide_inline_widgets_macros::InlineWidget;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#[derive(Debug, Clone)]
pub struct CallbackQueryData(pub String);
Loading

0 comments on commit 9daab71

Please sign in to comment.