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