use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use super::{MessageContent, MessageId, ScreenId};
fn default_true() -> bool {
true
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ChatAction {
Typing,
UploadPhoto,
UploadVideo,
UploadDocument,
FindLocation,
RecordVoice,
RecordVideo,
}
#[derive(Clone)]
pub enum InputSpec {
Text {
validator: Option<ValidatorFn>,
placeholder: Option<String>,
},
Photo,
Video,
Document,
Location,
Contact,
Choice {
options: Vec<String>,
},
}
impl std::fmt::Debug for InputSpec {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Text { placeholder, .. } => f
.debug_struct("Text")
.field("placeholder", placeholder)
.finish(),
Self::Photo => write!(f, "Photo"),
Self::Video => write!(f, "Video"),
Self::Document => write!(f, "Document"),
Self::Location => write!(f, "Location"),
Self::Contact => write!(f, "Contact"),
Self::Choice { options } => f.debug_struct("Choice").field("options", options).finish(),
}
}
}
pub type ValidatorFn = std::sync::Arc<dyn Fn(&str) -> Result<(), String> + Send + Sync>;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UserInfo {
pub id: super::UserId,
pub first_name: String,
pub last_name: Option<String>,
pub username: Option<String>,
pub language_code: Option<String>,
}
impl UserInfo {
#[must_use]
pub fn full_name(&self) -> String {
match &self.last_name {
Some(last) => format!("{} {}", self.first_name, last),
None => self.first_name.clone(),
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TrackedMessage {
pub message_id: MessageId,
pub content_type: crate::types::ContentType,
pub content_hash: u64,
pub text_hash: u64,
pub caption_hash: u64,
pub file_hash: u64,
pub keyboard_hash: u64,
}
impl TrackedMessage {
pub fn from_content(message_id: MessageId, content: &MessageContent) -> Self {
Self {
message_id,
content_type: content.content_type(),
content_hash: content.content_hash(),
text_hash: content.text_hash(),
caption_hash: content.caption_hash(),
file_hash: content.file_hash(),
keyboard_hash: content.keyboard_hash(),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct SentMessage {
pub message_id: MessageId,
pub chat_id: super::ChatId,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatState {
pub chat_id: super::ChatId,
pub current_screen: ScreenId,
pub active_bot_messages: Vec<TrackedMessage>,
pub pending_user_messages: Vec<MessageId>,
#[serde(skip)]
pub pending_callback_id: Option<String>,
pub data: HashMap<String, serde_json::Value>,
pub screen_stack: Vec<ScreenId>,
pub user: UserInfo,
#[serde(default)]
pub frozen_messages: Vec<MessageId>,
#[serde(default)]
pub(crate) reply_message_id: Option<MessageId>,
#[serde(default = "default_true")]
pub(crate) reply_sealed: bool,
}
impl ChatState {
pub fn new(chat_id: super::ChatId, user: UserInfo) -> Self {
Self {
chat_id,
current_screen: ScreenId::from("__initial__"),
active_bot_messages: Vec::new(),
pending_user_messages: Vec::new(),
pending_callback_id: None,
data: HashMap::new(),
screen_stack: Vec::new(),
user,
frozen_messages: Vec::new(),
reply_message_id: None,
reply_sealed: true,
}
}
}
#[derive(Debug, Clone, Default, PartialEq)]
pub enum CtxMode {
#[default]
Private,
Group {
trigger_message_id: Option<MessageId>,
},
Inline {
inline_message_id: String,
},
}