1
use std::fmt;
2

            
3
use ashpd::WindowIdentifier;
4
use futures_util::StreamExt;
5
use serde::Serialize;
6
use zbus::zvariant::{ObjectPath, OwnedValue, Type};
7

            
8
use super::DESTINATION;
9
use crate::dbus::{Error, ServiceError};
10

            
11
#[derive(Type)]
12
#[zvariant(signature = "o")]
13
#[doc(alias = "org.freedesktop.Secret.Prompt")]
14
pub struct Prompt<'a>(zbus::Proxy<'a>);
15

            
16
impl zbus::proxy::Defaults for Prompt<'_> {
17
    const INTERFACE: &'static Option<zbus::names::InterfaceName<'static>> = &Some(
18
        zbus::names::InterfaceName::from_static_str_unchecked("org.freedesktop.Secret.Prompt"),
19
    );
20
    const DESTINATION: &'static Option<zbus::names::BusName<'static>> = &Some(DESTINATION);
21
    const PATH: &'static Option<ObjectPath<'static>> = &None;
22
}
23

            
24
impl<'a> From<zbus::Proxy<'a>> for Prompt<'a> {
25
2
    fn from(value: zbus::Proxy<'a>) -> Self {
26
        Self(value)
27
    }
28
}
29

            
30
impl<'a> Prompt<'a> {
31
6
    pub async fn new<P>(
32
        connection: &zbus::Connection,
33
        object_path: P,
34
    ) -> Result<Option<Prompt<'a>>, Error>
35
    where
36
        P: TryInto<ObjectPath<'a>>,
37
        P::Error: Into<zbus::Error>,
38
    {
39
12
        let path = object_path.try_into().map_err(Into::into)?;
40
16
        if path != ObjectPath::default() {
41
4
            Ok(Some(
42
20
                zbus::proxy::Builder::new(connection)
43
4
                    .path(path)?
44
4
                    .build()
45
12
                    .await?,
46
            ))
47
        } else {
48
4
            Ok(None)
49
        }
50
    }
51

            
52
2
    pub fn inner(&self) -> &zbus::Proxy<'_> {
53
        &self.0
54
    }
55

            
56
8
    pub async fn prompt(&self, window_id: Option<WindowIdentifier>) -> Result<(), Error> {
57
2
        let id = match window_id {
58
            Some(id) => id.to_string(),
59
4
            None => Default::default(),
60
        };
61
10
        self.inner()
62
2
            .call_method("Prompt", &(id))
63
8
            .await
64
6
            .map_err::<ServiceError, _>(From::from)?;
65
2
        Ok(())
66
    }
67

            
68
    #[allow(unused)]
69
8
    pub async fn dismiss(&self) -> Result<(), Error> {
70
8
        self.inner()
71
2
            .call_method("Dismiss", &())
72
8
            .await
73
4
            .map_err::<ServiceError, _>(From::from)?;
74
2
        Ok(())
75
    }
76

            
77
2
    pub async fn receive_completed(
78
        &self,
79
        window_id: Option<WindowIdentifier>,
80
    ) -> Result<OwnedValue, Error> {
81
6
        let mut stream = self.inner().receive_signal("Completed").await?;
82
12
        let (value, _) = futures_util::try_join!(
83
6
            async {
84
8
                let message = stream.next().await.unwrap();
85
4
                let (dismissed, result) = message.body().deserialize::<(bool, OwnedValue)>()?;
86
4
                if dismissed {
87
2
                    Err(Error::Dismissed)
88
                } else {
89
2
                    Ok(result)
90
                }
91
            },
92
2
            self.prompt(window_id)
93
        )?;
94
2
        Ok(value)
95
    }
96
}
97

            
98
impl Serialize for Prompt<'_> {
99
    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
100
    where
101
        S: serde::Serializer,
102
    {
103
        ObjectPath::serialize(self.inner().path(), serializer)
104
    }
105
}
106

            
107
impl fmt::Debug for Prompt<'_> {
108
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109
        f.debug_tuple("Prompt")
110
            .field(&self.inner().path().as_str())
111
            .finish()
112
    }
113
}