Skip to main content

whatsapp_rust/features/
chatstate.rs

1//! Chat state (typing indicators) feature.
2
3use crate::client::Client;
4use log::debug;
5use wacore::StringEnum;
6use wacore_binary::builder::NodeBuilder;
7use wacore_binary::jid::Jid;
8
9/// Chat state type for typing indicators.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, StringEnum)]
11pub enum ChatStateType {
12    #[str = "composing"]
13    Composing,
14    #[str = "recording"]
15    Recording,
16    #[str = "paused"]
17    Paused,
18}
19
20/// Feature handle for chat state operations.
21pub struct Chatstate<'a> {
22    client: &'a Client,
23}
24
25impl<'a> Chatstate<'a> {
26    pub(crate) fn new(client: &'a Client) -> Self {
27        Self { client }
28    }
29
30    /// Send a chat state update to a recipient.
31    pub async fn send(
32        &self,
33        to: &Jid,
34        state: ChatStateType,
35    ) -> Result<(), crate::client::ClientError> {
36        debug!(target: "Chatstate", "Sending {} to {}", state, to);
37
38        let node = self.build_chatstate_node(to, state);
39        self.client.send_node(node).await
40    }
41
42    pub async fn send_composing(&self, to: &Jid) -> Result<(), crate::client::ClientError> {
43        self.send(to, ChatStateType::Composing).await
44    }
45
46    pub async fn send_recording(&self, to: &Jid) -> Result<(), crate::client::ClientError> {
47        self.send(to, ChatStateType::Recording).await
48    }
49
50    pub async fn send_paused(&self, to: &Jid) -> Result<(), crate::client::ClientError> {
51        self.send(to, ChatStateType::Paused).await
52    }
53
54    fn build_chatstate_node(&self, to: &Jid, state: ChatStateType) -> wacore_binary::node::Node {
55        let child = match state {
56            ChatStateType::Composing => NodeBuilder::new("composing").build(),
57            ChatStateType::Recording => {
58                NodeBuilder::new("composing").attr("media", "audio").build()
59            }
60            ChatStateType::Paused => NodeBuilder::new("paused").build(),
61        };
62
63        NodeBuilder::new("chatstate")
64            .attr("to", to.clone())
65            .children([child])
66            .build()
67    }
68}
69
70impl Client {
71    /// Access chat state operations.
72    pub fn chatstate(&self) -> Chatstate<'_> {
73        Chatstate::new(self)
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    #[test]
82    fn test_chat_state_type_string_enum() {
83        assert_eq!(ChatStateType::Composing.as_str(), "composing");
84        assert_eq!(ChatStateType::Recording.to_string(), "recording");
85        assert_eq!(
86            ChatStateType::try_from("paused").unwrap(),
87            ChatStateType::Paused
88        );
89    }
90}